﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using FFPAnalyze;
using System.Threading;
namespace FFPVideo
{
    public partial class Video : VideoControl.Video
    {
        /*
         *  基本控制
         *      上下左右高低远近明暗
         *  巡航识别
         *      巡航，识别，报警
         *  录像
         *      录像
         *  抓拍
         *      抓拍
         *      
         *  文件系统
         *      设备配置路径
         *      录像路径
         *      报警图片路径
         *      抓拍路径
         *      
         */

        public event EventHandler<HorizonEventArgs> HorizonCallback;
        public event EventHandler<VerticalEventArgs> VerticalCallback;
        public class HorizonEventArgs : EventArgs
        {
            public short Horizon { get; private set; }
            public HorizonEventArgs(short horizon)
            {
                this.Horizon = horizon;
            }
        }
        public class VerticalEventArgs : EventArgs
        {
            public short Vertical { get; private set; }
            public VerticalEventArgs(short vertical)
            {
                this.Vertical = vertical;
            }
        }

        short horizon, vertical;
        public short Horizon { get { return horizon; } private set { horizon = value; } }
        public short Vertical { get { return vertical; } private set { vertical = value; } }


        /// <summary>
        /// 报警帧回调委托
        /// </summary>
        /// <param name="frames"></param>
        public delegate void AlarmCallback(Bitmap frames);

        AlarmCallback Alarm;
        public void SetAlarm(AlarmCallback alarm)
        {
            this.Alarm = alarm;
        }

        void AlarmFrame(Bitmap frame)
        {
            this.Alarm(frame);
         //   if(frame!=null)
         //   MessageBox.Show("alarm frame");
         //   else
         //      MessageBox.Show("alarm finished");
        }
     
        Analyze analyze = new Analyze();
       // FileManager.FileManager fmgr = new FileManager.FileManager();
        public Video()
        {
            this.analyze.GetImagePath = new Analyze.GetImagePathCallback(this.GetImagePath);
            this.analyze.Alarm = new Analyze.AlarmCallback(AlarmFrame);
          //  FileManager.FileManager.Initialize();
              InitializeComponent();
        }
        /// <summary>
        /// 从文件管理类中得到报警图片要保存的路径
        /// </summary>
        /// <returns>返回报警图片保存的路径</returns>
        private string GetImagePath(bool isFirstFrame)
        {
            return FileManager.FileManager.GetAlarmFileName(this.DeviceArea, this.DeviceName, isFirstFrame,this.Horizon,this.Vertical);
        }
        protected override void OnStreamVideo(IntPtr pBuf, int w, int h)
        {
          //  base.OnStreamVideo(pBuf, w, h);
            analyze.InputVideoStreamYV12(pBuf, ref w, ref h);
        }

        #region Cruise
        /// <summary>
        /// 依据参数打开和关闭识别
        /// </summary>
        /// <param name="open">为true时，打开识别，为false时关闭</param>
        public void Analyze(bool open)
        {
            this.isAnalyze = open;

            if (this.isAnalyze)
            {
                if (this.ThreadStartCruiseAndAnalyze == null || !this.ThreadStartCruiseAndAnalyze.IsAlive)
                {
                    this.ThreadStartCruiseAndAnalyze = new Thread(new ThreadStart(StartCruiseAndAnalyze));
                    this.ThreadStartCruiseAndAnalyze.Start();
                }
            }
        }
        /// <summary>
        /// 依据参数打开和关闭巡航
        /// </summary>
        /// <param name="open">为true时，打开巡航，为false时关闭巡航</param>
        public void Cruise(bool open)
        {
            this.isCruising = open;

            if (this.isCruising)
            {
                if (this.ThreadStartCruiseAndAnalyze == null || !this.ThreadStartCruiseAndAnalyze.IsAlive)
                {
                    this.ThreadStartCruiseAndAnalyze = new Thread(new ThreadStart(StartCruiseAndAnalyze));
                    this.ThreadStartCruiseAndAnalyze.Start();
                }
            }
        }

        private bool isCruising = false;

        public bool IsCruising
        {
            get { return isCruising; }
           // set { isCruising = value; }
        }
        bool isAnalyze = false;

        public bool IsAnalyze
        {
            get { return isAnalyze; }
           // set { isAnalyze = value; }
        }
        Thread ThreadStartCruiseAndAnalyze= null;
        /// <summary>
        /// 巡航和识别线程开启函数
        /// </summary>
        void StartCruiseAndAnalyze()
        {
            while (isAnalyze || isCruising)
            {
                if (isAnalyze)
                {
                    this.GetHorizon();
                    Thread.Sleep(1000);
                    this.GetHorizon();
                    this.analyze.StartAnalyze();
                }

                if (isCruising)
                {
                    this.PTZControlDirect(this.VideoChannel, PTZCommandEnum.PAN_RIGHT, false, 3);
                    Thread.Sleep(2000);
                    this.PTZControlDirect(this.VideoChannel, PTZCommandEnum.PAN_RIGHT, true, 3);
                    
                }

                Thread.Sleep(3000);
               
            }
        }
        public void AbortThread()
        {
            if (this.ThreadStartCruiseAndAnalyze == null)
                return;
            if (this.ThreadStartCruiseAndAnalyze.IsAlive)
                ThreadStartCruiseAndAnalyze.Abort();
            this.isAnalyze = false;
            this.isCruising = false;
        }
        #endregion

        #region Record & Snap

        public bool StartRecord()
        {
            if (DeviceArea == null || DeviceName == null)
                throw new InvalidOperationException();
            string path = FileManager.FileManager.GetRecordingFileName(DeviceArea, DeviceName);
            this.StartRecord(path);
            return true;
        }
        public bool Snap(ImageTypeEnum ImageType, ImageSizeEnum ImageSize, ImageQualityEnum ImageQuality)
        {
            if (DeviceArea == null || DeviceName == null)
                throw new InvalidOperationException();
            string path = FileManager.FileManager.GetSnapFileName(DeviceArea, DeviceName);
            this.SnapsortFromDevice(path, ImageType, ImageSize, ImageQuality);
            return true;
        }
        public bool Snap()
        {
            return Snap(ImageTypeEnum.Jpeg, ImageSizeEnum.CIF, ImageQualityEnum.Standard);
        }
        #endregion

        #region PTZ Control 

        private byte speed = 4;

        public byte Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        PTZCommandEnum PTZCE = PTZCommandEnum.TILT_UP;
        public void PTZUp()
        {
            PTZCE = PTZCommandEnum.TILT_UP;
            PTZControlDirect(PTZCommandEnum.TILT_UP, false, speed);
        }
        public void PTZDown()
        {
            PTZCE = PTZCommandEnum.TILT_DOWN;
            PTZControlDirect(PTZCommandEnum.TILT_DOWN, false, speed);
        }
        public void PTZLeft()
        {
            PTZCE = PTZCommandEnum.PAN_LEFT;
            PTZControlDirect(PTZCommandEnum.PAN_LEFT, false, speed);
        }
        public void PTZRight()
        {
            PTZCE = PTZCommandEnum.PAN_RIGHT;
            PTZControlDirect(PTZCommandEnum.PAN_RIGHT, false, speed);
        }
        public void PTZZoomIn()
        {
            PTZControlDirect(PTZCommandEnum.ZOOM_IN, false, speed);
        }
        public void PTZZoomOut()
        {
            PTZControlDirect(PTZCommandEnum.ZOOM_OUT, false, speed);
        }
        public void PTZFar()
        {
            PTZControlDirect(PTZCommandEnum.FOCUS_FAR, false, speed);
        }
        public void PTZNear()
        {
            PTZControlDirect(PTZCommandEnum.FOCUS_NEAR, false, speed);
        }

        public void PTZStop()
        {
            PTZControlDirect(PTZCE, true, speed);

            switch (PTZCE)
            {
                case PTZCommandEnum.TILT_UP:
                case PTZCommandEnum.TILT_DOWN:
                    this.GetVertical();
                    break;
                case PTZCommandEnum.PAN_LEFT:
                case PTZCommandEnum.PAN_RIGHT:
                    this.GetHorizon();
                    break;
                case PTZCommandEnum.UP_LEFT:
                case PTZCommandEnum.UP_RIGHT:
                case PTZCommandEnum.DOWN_LEFT:
                case PTZCommandEnum.DOWN_RIGHT:
                    this.GetHorizon();
                    this.GetVertical();
                    break;
                default:
                    break;
            }
        }

        protected override void OnOpen()
        {
            base.OnOpen();

            this.EstablishRouteway485(new SerialReceiveCallback(SerialReceiveCB));
        }

        public void GoHorizon(int angle)
        {
            if (angle < 0 || angle > 359) return;

            byte[] byteAngleHorizon = System.BitConverter.GetBytes(angle * 100);
            byte[] msgGoHorizon = new byte[] { 0xFF, deviceAddress, 0x00, 0x4B, byteAngleHorizon[1], byteAngleHorizon[2], 0x00 };

            for (int i = 1; i < 6; i++)
            {
                msgGoHorizon[6] += msgGoHorizon[i];
            }

            this.SendToRouteway485(1, msgGoHorizon);

        }

        public void GoVertical(int angle)
        {
            if (angle < -75 || angle > 40) return;
            angle = -angle;
            if (angle < 0) angle = angle * 100 + 36000;
            else angle *= 100;
            byte[] byteAngleHorizon = System.BitConverter.GetBytes(angle);
            byte[] msgGoVerical = new byte[] { 0xFF, deviceAddress, 0x00, 0x4D, byteAngleHorizon[1], byteAngleHorizon[2], 0x00 };

            for (int i = 1; i < 6; i++)
            {
                msgGoVerical[6] += msgGoVerical[i];
            }

            this.SendToRouteway485(1, msgGoVerical);
        }

        public void GetHorizon()
        {
            byte[] msgGetHorizon = new byte[] { 0xFF, deviceAddress, 0x00, 0x51, 0x00, 0x00, 0x59 };

            this.SendToRouteway485(1, msgGetHorizon);
        }

        public void GetVertical()
        {
            byte[] msgGetVertical = new byte[] { 0xFF, deviceAddress, 0x00, 0x53, 0x00, 0x00, 0x5B };

            this.SendToRouteway485(1, msgGetVertical);
        }

        List<byte> ReceiveMessage = new List<byte>();
        private void SerialReceiveCB(byte[] Data)
        {
            if (ReceiveMessage.Count >= 7
                || ReceiveMessage.Count > 0 && ReceiveMessage[0] != 0xFF)
                ReceiveMessage.Clear();

            foreach (var item in Data)
            {
                ReceiveMessage.Add(item);
            }

            if (ReceiveMessage.Count == 7
                && ReceiveMessage[0] == 0xFF)
            {
                switch (ReceiveMessage[0x03])
                {
                    case 0x59:  //水平角
                        ushort horizon = System.BitConverter.ToUInt16(new byte[] { ReceiveMessage[5], ReceiveMessage[4] }, 0);
                        this.horizon = Convert.ToInt16(horizon / 100);
                        if (HorizonCallback != null) HorizonCallback(this, new HorizonEventArgs(this.horizon));
                        break;
                    case 0x5B:  //垂直角
                        ushort vertical = System.BitConverter.ToUInt16(new byte[] { ReceiveMessage[5], ReceiveMessage[4] }, 0);
                        this.vertical = vertical < 18000 ? 
                            Convert.ToInt16(-vertical / 100) : 
                            Convert.ToInt16((36000 - vertical) / 100);
                        if (VerticalCallback != null) VerticalCallback(this, new VerticalEventArgs(this.vertical));
                        break;
                    default:
                        break;
                }
            }
        }

        protected override void OnClose()
        {
            this.ShutdownRouteway485();

            base.OnClose();
        }

        #endregion
    }
}
